package agend.agents;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;

import com.google.gdata.util.AuthenticationException;

import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import GoogleServices.GoogleCalendarCalls;
import agend.behaviours.SwitcherBehaviour;
import agend.behaviuors.android.AndroidCredentialBheaviour;

import agend.dlv.DlvMaker;
import dto.utils.DataTransferObject;
import dto.utils.DisponibilitaSettimanale;
import dto.utils.PeriodiInattivita;

/** Agente alla base dell'applicazione al quale vengono aggiunti due
 * behaviours, uno che richiede un appuntamento e l'altro che sta in attesa
 * di una richiesta
 */
public class AgendAgent extends Agent {

	private static final long serialVersionUID = 1L;

	private GoogleCalendarCalls googleServices;
	private String username;
	private String password;
	private DlvMaker dlvMaker;
	private DisponibilitaSettimanale disponibilitaSettimanale;
	private HashMap<String ,DataTransferObject> mapOfEvents;
	

	@Override
	protected void setup() {
	
		super.setup();

		loadDisponibilitaSettimanaleFromFile();
		dlvMaker = new DlvMaker(getAID().getLocalName());

		String [] credenziali = null;

		if(getArguments() instanceof String[])  				// Effettuo questo instanceof perche' dal main setto le credenziali come object[] a dal behaviour come object
			credenziali = (String[]) getArguments();
		else
			credenziali = (String[]) getArguments()[0];

		username = credenziali[0];
		password = credenziali[1];

		try {

			googleServices=new GoogleCalendarCalls(username, password);

			if(credenziali.length == 3)
				addBehaviour(new AndroidCredentialBheaviour(ACLMessage.CONFIRM, new AID(credenziali[2], AID.ISLOCALNAME)));

		} catch (AuthenticationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

			if(credenziali.length == 3)
				addBehaviour(new AndroidCredentialBheaviour(ACLMessage.FAILURE, new AID(credenziali[2], AID.ISLOCALNAME)));
		}


		System.out.println("Agent "+getAID().getName()+" start");

		System.out.println("Le mie credenziali sono " + username +" " + password);

		//registrazione servizio sul df
		registraServizio();


		addBehaviour(new SwitcherBehaviour());							//Proporre appuntamenti
	}

	@Override
	protected void takeDown() {
		// TODO Auto-generated method stub
		super.takeDown();

		try {
			DFService.deregister(this);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

		// Printout a dismissal message
		System.out.println("Terminando "+getAID().getLocalName());

	}

	public GoogleCalendarCalls getGoogleServices(){
		return googleServices;
	}

	public DlvMaker getDlvMaker() {
		return dlvMaker;
	}	

	private void registraServizio(){

		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		System.out.println(getDefaultDF());
		ServiceDescription sd = new ServiceDescription();
		sd.setType("calendar-service");
		sd.setName(getAID().getLocalName());
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

	}


	public void setDisponibilitaSettimanale(
			DisponibilitaSettimanale disponibilitaSettimanale) {
		this.disponibilitaSettimanale = disponibilitaSettimanale;
	}

	public PeriodiInattivita getPeriodiInattivita()
	{
		return new PeriodiInattivita();
	}

	public DisponibilitaSettimanale getDisponibilitaSettimanale()
	{
		return disponibilitaSettimanale;
	}

	/**
	 * Se il file delle disponibilit� serilizzato esiste carico 
	 * le disponibilit� da file altrimenti faccio una new 
	 */
	private void loadDisponibilitaSettimanaleFromFile(){

		String fileName = "filesImpostazioni/"+getLocalName()+"_Availability.dat";
		File file = new File(fileName);

		if(file.exists()){
			ObjectInputStream objectInputStream;
			try {
				objectInputStream = new ObjectInputStream(new FileInputStream(file));
				try {
					disponibilitaSettimanale = (DisponibilitaSettimanale) objectInputStream.readObject();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		else
			disponibilitaSettimanale = new DisponibilitaSettimanale();

	}

	/**
	 * Funzione che gestisce il caricamento della mappa degli eventi
	 * @return la mappa degli eventi
	 */
	private void loadMapOfEvents(){

		String nameFileOfEvents = "filesEventi/"+getLocalName()+"_ListOfEvent.dat";
		File file = new File(nameFileOfEvents);

		if(file.exists()){


			ObjectInputStream objectInputStream;
			try {
				objectInputStream = new ObjectInputStream(new FileInputStream(file));
				try {
					mapOfEvents = (HashMap<String, DataTransferObject>) objectInputStream.readObject();
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		else
			mapOfEvents = new HashMap<String, DataTransferObject>();


	}


	/**
	 * Funzione che gestisce il salvataggio della mappa degli eventi
	 * @return la mappa degli eventi
	 */
	private  void saveMapOfEvents(){

		String nameFileOfEvents = "filesEventi/"+getLocalName()+"_ListOfEvent.dat";
		File file = new File(nameFileOfEvents);
		ObjectOutputStream objectOutputStream;
		try {
			objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
			objectOutputStream.writeObject(mapOfEvents);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}


	/**
	 * Cerca un evento all ' interno della mappa degli eventi
	 * @param idEvento
	 * @return ritora l'evento con chiave idEvento se esiste altrimenti ritorna null
	 */
	public DataTransferObject findEventByMap(String idEvento){

		loadMapOfEvents();

		for(String eventKey : mapOfEvents.keySet())
			if(eventKey.equals(idEvento))
				return mapOfEvents.get(idEvento);

		return null;

	}

	/**
	 * Aggiunge un evento alla mappa 
	 * @param idEvento
	 * @param dto
	 */
	public void addEventsToMap(String idEvento , DataTransferObject dto){

		loadMapOfEvents();
		mapOfEvents.put(idEvento,dto);
		saveMapOfEvents();

	}

	public void removeEventsToMap(String idEvento){

		loadMapOfEvents();
		mapOfEvents.remove(idEvento);
		saveMapOfEvents();
	}
}
